from typing import Annotated
from fastapi import APIRouter, Depends
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
from config import Config
from datetime import datetime, timezone
from utility.security import verify_password
from common import response_code, exception
from crud.systems import user as admin_user_crud
from crud.users import users as common_user_crud
import models
import jwt
from sqlmodel import Session
from dependencies import get_session, SessionDep, engine

router = APIRouter()

# 这个实例将用于在API端点中验证管理员、患者、医生用户的Bearer Token
oauth2_scheme_admin = OAuth2PasswordBearer(tokenUrl=Config.ADMIN_TOKEN_URL)
oauth2_scheme_patient = OAuth2PasswordBearer(tokenUrl=Config.PATIENT_TOKEN_URL)
oauth2_scheme_doctor = OAuth2PasswordBearer(tokenUrl=Config.DOCTOR_TOKEN_URL)


# 获取当前系统用户
def get_current_sys_user(token: str = Depends(oauth2_scheme_admin), session: Session = Depends(get_session)):
    credentials_exception = exception.create_http_exception(
        status_code=400, detail="无效的认证令牌"
    )
    try:
        payload = jwt.decode(token, Config.SECRET_KEY, algorithms=["HS256"])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        sys_user = admin_user_crud.get_current_user(session=session, username=username)
    except jwt.ExpiredSignatureError:
        raise exception.create_http_exception(status_code=401, detail="令牌已过期")
    except jwt.InvalidTokenError:
        raise credentials_exception
    return sys_user


# 获取当前患者用户
def get_current_patient_user(token: str = Depends(oauth2_scheme_patient), session: Session = Depends(get_session)):
    credentials_exception = exception.create_http_exception(
        status_code=400, detail="无效的认证令牌"
    )
    try:
        payload = jwt.decode(token, Config.SECRET_KEY, algorithms=["HS256"])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        patient_user = common_user_crud.get_current_user(session=session, username=username, type=1)
    except jwt.ExpiredSignatureError:
        raise exception.create_http_exception(status_code=401, detail="令牌已过期")
    except jwt.InvalidTokenError:
        raise credentials_exception

    return patient_user


# 获取当前医生用户
def get_current_doctor_user(token: str = Depends(oauth2_scheme_doctor), session: Session = Depends(get_session)):
    credentials_exception = exception.create_http_exception(
        status_code=400, detail="无效的认证令牌"
    )
    try:
        payload = jwt.decode(token, Config.SECRET_KEY, algorithms=["HS256"])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        doctor_user = common_user_crud.get_current_user(session=session, username=username, type=2)
    except jwt.ExpiredSignatureError:
        raise exception.create_http_exception(status_code=401, detail="令牌已过期")
    except jwt.InvalidTokenError:
        raise credentials_exception

    return doctor_user


# 后台用户登录
@router.post(
    "/api/admin/login",
    tags=["身份认证"],
    summary="后台用户登录",
    response_model=models.RespJsonLogin,
)
async def admin_login(
    form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
    response: models.RespJsonLogin = Depends(
        response_code.RespSuccessJson.resp_200_login
    ),
    session: Session = Depends(get_session),
):
    username = form_data.username
    password = form_data.password

    user = admin_user_crud.get_current_user(session=session, username=username)

    if not user:
        raise exception.create_http_exception(status_code=400, detail="当前用户不存在")
    elif not verify_password(password, user.password):
        raise exception.create_http_exception(
            status_code=400, detail="用户名和密码不匹配"
        )

    # 要编码的数据
    payload = {
        "sub": username,
        "exp": datetime.now(timezone.utc) + Config.TOKEN_EXPIRE_TIME,  # 过期时间
    }
    # 生成token
    access_token = jwt.encode(payload, Config.SECRET_KEY, algorithm="HS256")

    response.access_token = access_token
    response.msg = "登录成功"

    return response


# 患者登录
@router.post(
    "/api/patient/login",
    tags=["身份认证"],
    summary="患者登录",
    response_model=models.RespJsonLogin,
)
async def patient_login(
    form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
    response: models.RespJsonLogin = Depends(
        response_code.RespSuccessJson.resp_200_login
    ),
    session: Session = Depends(get_session),
):
    username = form_data.username
    password = form_data.password
    user = common_user_crud.get_current_user(session=session, username=username, type=1)

    if not user:
        raise exception.create_http_exception(status_code=400, detail="当前用户不存在")
    elif not verify_password(password, user.password):
        raise exception.create_http_exception(
            status_code=400, detail="用户名和密码不匹配"
        )

    # 要编码的数据
    payload = {
        "sub": username,
        "exp": datetime.now(timezone.utc) + Config.TOKEN_EXPIRE_TIME,  # 过期时间
    }
    # 生成token
    access_token = jwt.encode(payload, Config.SECRET_KEY, algorithm="HS256")

    response.access_token = access_token
    response.msg = "登录成功"

    return response


# 医生登录
@router.post(
    "/api/doctor/login",
    tags=["身份认证"],
    summary="医生登录",
    response_model=models.RespJsonLogin,
)
async def doctor_login(
    form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
    response: models.RespJsonLogin = Depends(
        response_code.RespSuccessJson.resp_200_login
    ),
    session: Session = Depends(get_session),
):
    username = form_data.username
    password = form_data.password
    user = common_user_crud.get_current_user(session=session, username=username, type=2)

    if not user:
        raise exception.create_http_exception(status_code=400, detail="当前用户不存在")
    elif not verify_password(password, user.password):
        raise exception.create_http_exception(
            status_code=400, detail="用户名和密码不匹配"
        )

    # 要编码的数据
    payload = {
        "sub": username,
        "exp": datetime.now(timezone.utc) + Config.TOKEN_EXPIRE_TIME,  # 过期时间
    }

    # 生成token
    access_token = jwt.encode(payload, Config.SECRET_KEY, algorithm="HS256")

    response.access_token = access_token
    response.msg = "登录成功"

    return response
